#include "bigint.h"



#include <iostream>

#include <vector>

#include <algorithm>



using namespace std;



BigInt v_pos(const BigInt &a);

void zeral(vector<int> &a);



BigInt::BigInt()

{

    signe = true;

}



BigInt::BigInt(const string expr)

{

    signe = true ;

    int decal = 0 ;

    if (expr[0] == '-')

    {

        decal = 1;

        signe = false ;

    }



    for (int i= expr.size() -1 ; i >= decal ; i--) tab.push_back(expr[i] -'0');



    zeral(tab);

}



void zeral(vector<int> &a)

{

    while (a[a.size() - 1] == 0) a.pop_back(); // 0015 devient 15.

}



BigInt::BigInt(const BigInt &a)

{

    tab = a.tab ;

    signe=a.signe;

}



bool BigInt::operator==(const BigInt& a)

{

    if (a.tab.size() != tab.size()) return false ;

    if (signe != a.signe) return false ;



    for (int i = tab.size()-1 ; i >=0 ; i--)

    {

        if (tab[i] != a.tab[i]) return false;

    }

    return true ;

}



bool BigInt::operator!=(const BigInt& a)

{

    if (*this==a) return false ;

    return true ;

}



bool BigInt::operator>(const BigInt& a)

{

    if (tab.size() < a.tab.size()) return false ;

    if (a.tab.size() < tab.size()) return true;
    
    if (signe && !a.signe) return true ;
    if (!a.signe && signe) return false ;



    for (int i = tab.size() -1 ; i >=0 ; i--)

    {

        if (tab[i] > a.tab[i] ) return true ;

        if (tab[i] < a.tab[i] ) return false ;

    }



    return false;

}



bool BigInt::operator>=(const BigInt& a)

{

    return (*this>a || *this==a);

}



bool BigInt::operator<(const BigInt& a)

{

    return !( *this>=a );

}



bool BigInt::operator<=(const BigInt& a)

{

    return (*this<a || *this==a);

}



BigInt BigInt::operator+(const BigInt& a)

{

    BigInt add;



    if (signe == a.signe)

    {

        add=*this;

        add+=a;

    }



    // on est ici dans les cas où le deuxième BigInt est négatif, dans ce cas on doit vérifier si ça ne va pas changer le signe final.



    else if (v_pos(*this) > v_pos(a) )

    {

        add=*this;

        add-=a;

    }



    // 10-14 devient 14-10, mais avec un signe négatif.

    else

    {

        add=a;

        add-=*this;

    }



    zeral(add.tab);



    return add;



}



BigInt v_pos(const BigInt &a)

{

    BigInt pos(a);

    pos.signe = true ; // on cherche à trouver la valeur absolue, on crée donc un nouvel BigInt avec le signe positif dans tout les cas

    return pos;

}



BigInt BigInt::operator-(const BigInt& a)

{

    BigInt sub(*this);



    // a-b = a+(-b)



    sub=sub+(-a);



    zeral(sub.tab);



    return sub ;

}



BigInt BigInt::operator-() const

{

    BigInt opp(*this);

    opp.signe = (!signe);

    return opp;

}



BigInt BigInt::operator++()

{

    BigInt inc(*this);

    BigInt tmp("1");

    inc+=tmp;

    return inc;

}



BigInt BigInt::operator--()

{

    BigInt inc(*this);

    BigInt tmp("1");

    inc-=tmp;

    return inc;

}



BigInt& BigInt::operator+=(const BigInt& a)

{

    int l_min = min(a.tab.size(),tab.size());

    int l_max = max(a.tab.size(),tab.size());



    int ret = 0;



    for (int i = 0 ; i < l_min ; i++)

    {

        tab[i]+=a.tab[i]+ret;

        ret = 0;

        if (tab[i] >=10)

        {

            tab[i]%=10;

            ret = 1;

        }

    }



    for (int i = l_min ; i < l_max ; i++)

    {



        if (l_max == a.tab.size())

        {

            tab.push_back(ret+a.tab[i]);

            ret = 0;



            if (tab[i] >= 10)

            {

                tab[i]%=10;

                ret = 1;

            }

        }

        else if (l_max == tab.size())

        {

            if (ret == 0) break ; // la retenue est à 0, donc les valeurs suivantes de tab[i] ne pourront pas changer, et étant donné qu'ellessont déjà dans le tableau c'est inutile de continuer.



            tab[i]+=ret;

            ret=0;

            if (tab[i] >=10)

            {

                tab[i]%=10;

                ret=1;

            }

        }

    }
    
    if (ret == 1) tab.push_back(1);



    return *this ;

}



BigInt& BigInt::operator-=(const BigInt& a)

{

    int l_min = min(a.tab.size(),tab.size());

    int l_max = max(a.tab.size(),tab.size());



    int ret = 0;



    for (int i = 0 ; i < l_min ; i++)

    {

        //cout << "i =" << i << "          tab[i] = " << tab[i] << "        a.tab[i] = " << a.tab[i] ;

        tab[i]-=a.tab[i]+ret;

        ret = 0;



        //cout << "tab[i] - a.tab[i] = " << tab[i] << endl ;

        if (tab[i] <0)

        {

               /* if (i == l_max-1) tab[i]*=-1;

                else

                {*/

                    tab[i]+=10;

                    ret=1;

                //}

        }

    }



    for (int i = l_min ; i < l_max ; i++)

    {



        if (l_max == a.tab.size())

        {

            tab.push_back(ret+a.tab[i]);

            ret = 0;



            if (tab[i] <0)

            {

               /* if (i == l_max-1) tab[i]*=-1;

                else

                {*/

                    tab[i]+=10;

                    ret=1;

                //}

            }

        }

        else if (l_max == tab.size())

        {

            if (ret == 0) break ; // la retenue est à 0, donc les valeurs suivantes de tab[i] ne pourront pas changer, et étant donné qu'ellessont déjà dans le tableau c'est inutile de continuer.



            tab[i]+=ret;

            ret=0;

            if (tab[i] < 0)

            {

               /* if (i == l_max-1) tab[i]*=-1;

                else

                {*/

                    tab[i]+=10;

                    ret=1;

                //}

            }

        }

    }



    return *this ;

}



void BigInt::Affiche() const

{

    if (!signe) cout << " - ";



    for (int i = tab.size() -1 ; i >= 0 ; i--) cout << tab[i];



    cout << endl << endl ;



}



BigInt BigInt::operator*(const BigInt& a)

{

    BigInt mul;



    if (tab.size() >= a.tab.size())

    {

        if (signe != a.signe) mul=-(*this);// le produit sera donc négatif

        else mul=*this;



        mul*=a;

    }

   else

    {

        if (signe != a.signe) mul=-(a);// le produit sera donc négatif

        else mul=a;



        mul*=*this;

    }



    return mul;



}



BigInt& BigInt::operator*=(const BigInt& a)

{

    int ret = 0 ;



    BigInt res;

    res.tab.resize(tab.size() + a.tab.size()-1);



    for (int i = 0 ; i < tab.size() ; i ++)

    {

        for (int j = 0 ; j < a.tab.size() ; j++)

        {

            res.tab[i+j]+= tab[i]*a.tab[j]  + ret ;

            ret = 0 ;



            if (res.tab[i+j] >= 10)

            {

                ret = res.tab[i+j] /10 ;

                res.tab[i+j]%=10 ;

            }

        }

    }

    *this = res ;



    return *this;

}


int BigInt::nb_chiffre()
{
	return tab.size();
}

int BigInt::somme_chiffre()
{
	int somme = 0 ;
	for (int i = 0 ; i < tab.size() ; i++) somme+= tab[i];
	return somme;
}






















